package com.example.smartagriculture.handler;

import com.example.smartagriculture.controller.MeteorologyMsgController;
import com.example.smartagriculture.service.IMeteorologyMsgService;
import com.example.smartagriculture.service.serviceImpl.MeteorologyMsgServiceImpl;
import com.example.smartagriculture.utils.ChannelMap;
import io.netty.channel.*;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
@ChannelHandler.Sharable
public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    @Resource
    private MeteorologyMsgController meteorologyMsgController;
//    @Bean
//    public MeteorologyMsgController getmeteorologyMsgController(){
//        meteorologyMsgController = new MeteorologyMsgController();
//        return meteorologyMsgController;
//    }


    /**
     * 功能描述: 有客户端连接服务器会触发此函数
     * @Author keLe
     * @Date 2022/8/26
     * @param  ctx 通道
     * @return void
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = insocket.getAddress().getHostAddress();
        int clientPort = insocket.getPort();
        //获取连接通道唯一标识
        ChannelId channelId = ctx.channel().id();
        //如果map中不包含此连接，就保存连接
        if (ChannelMap.getChannelMap().containsKey(channelId)) {
            log.info("客户端:{},是连接状态，连接通道数量:{} ",channelId,ChannelMap.getChannelMap().size());
        } else {
            //保存连接
            ChannelMap.addChannel(channelId, ctx.channel());
            log.info("报存客户端:{},连接netty服务器[IP:{}-->PORT:{}]",channelId, clientIp,clientPort);
            log.info("连接通道数量channelActive: {}",ChannelMap.getChannelMap().size());
        }
        // 清除过期客户端
        this.removeOutTimeChannel();
    }

    /**
     * 清除过期客户端
     */
    public void removeOutTimeChannel(){
        ConcurrentHashMap.KeySetView<ChannelId, Channel> channelIds = ChannelMap.getChannelMap().keySet();
        for (ChannelId channelId : channelIds) {
            Channel channel = ChannelMap.getChannelByName(channelId);
            if (!channel.isActive()||!channel.isOpen()) {
//                System.out.println("异常通道"+channelId);
                ChannelMap.getChannelMap().remove(channelId);
                log.info("移除客户端:"+channelId);
            }
        }
    }

    /**
     * 功能描述: 有客户端终止连接服务器会触发此函数
     * @Author keLe
     * @Date 2022/8/26
     * @param  ctx 通道处理程序上下文
     * @return void
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        InetSocketAddress inSocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = inSocket.getAddress().getHostAddress();
        ChannelId channelId = ctx.channel().id();
        // 其他处理

    }

    /**
     * 功能描述: 有客户端发消息会触发此函数
     * @Author keLe
     * @Date 2022/8/26
     * @param  ctx 通道处理程序上下文
     * @param  msg 客户端发送的消息
     * @return void
     */

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        log.info("加载客户端报文,客户端id:{},客户端消息:{}",ctx.channel().id(), msg);
        //System.out.println(msg);
        log.info((String) msg);
        String data = String.valueOf(msg);
        //System.out.println(data);
        StringBuilder s = new StringBuilder(new String());
        for (int i = 0; i < data.length(); i += 2) {    //UTF-8-1 ASCII
            int sum;

            char c1 = data.charAt(i);
            char c2 = data.charAt(i + 1);
            int a1 = Integer.parseInt(String.valueOf(c1), 16);
            int a2 = Integer.parseInt(String.valueOf(c2), 16);
            sum = a1 * 16 + a2;
            char c = (char)sum;
            s.append(c);
            //System.out.print(c);

        }
//        System.out.println(s);
        //MapUtil mapUtil = new MapUtil(s.toString());
        //mapUtil.sortedHeadTailTwoAverageMapStrInt();
        //mapUtil.averageMapStrInt();
//        mapUtil.printMapStrInt();
        //System.out.println(321);
        //System.out.println("this:"+this);
        //System.out.println(meteorologyMsgServiceImpl);
        //meteorologyMsgServiceImpl.jsonToObj(s.toString());
        System.out.println("11111111111111meteorologyMsgController:"+meteorologyMsgController);
        meteorologyMsgController.sendMsg(s.toString());
//        HashMap<String, Integer> Packet = mapUtil.getMapStrInt();
        //Integer water = Integer.parseInt(data.substring(6,10),16);
//        log.info("当前水位:{}cm",water);
        //log.info("当前水位:{}cm",water);

//        响应客户端
        this.channelWrite(ctx.channel().id(), msg);
        //将传递过来的内容转换为ByteBuf对象
//        ByteBuf buf = (ByteBuf) msg;
//        //和文件IO一样，用一个字节数组读数据
//        byte[] reg = new byte[buf.readableBytes()];
//        buf.readBytes(reg);
//        //将读取的数据转换为字符串
//        String body = new String(reg, "UTF-8");
//        //给客户端传递的内容，同样也要转换成ByteBuf对象
//        Date dNow = new Date( );
//        SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss");
//        String respMsg = body+ft.format(dNow);
//        System.out.println("服务器当前时间是："+ft.format(dNow));
//        ByteBuf respByteBuf = Unpooled.copiedBuffer(respMsg.getBytes());
//        //调用write方法，通知并将数据传给outboundHand
//        ctx.write(respByteBuf);

    }

   /* @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        String bytes = "01 03 00 02 00 01 25 CA";
        ctx.writeAndFlush(bytes);
    }*/

    /**
     * 功能描述: 服务端给客户端发送消息
     * @Author keLe
     * @Date 2022/8/26
     * @param  channelId 连接通道唯一id
     * @param  msg 需要发送的消息内容
     * @return void
     */
    public void channelWrite(ChannelId channelId, Object msg) throws Exception {
        Channel channel = ChannelMap.getChannelMap().get(channelId);
        if (channel == null) {
            log.info("通道:{},不存在",channelId);
            return;
        }
        if (msg == null || msg == "") {
            log.info("服务端响应空的消息");
            return;
        }
        //将客户端的信息直接返回写入ctx
        channel.write(msg);
        //刷新缓存区
        channel.flush();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        String socketString = ctx.channel().remoteAddress().toString();
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                log.info("Client:{},READER_IDLE 读超时",socketString);
                ctx.disconnect();
                Channel channel = ctx.channel();
                ChannelId id = channel.id();
                ChannelMap.removeChannelByName(id);
            } else if (event.state() == IdleState.WRITER_IDLE) {
                log.info("Client:{}, WRITER_IDLE 写超时",socketString);
                ctx.disconnect();
                Channel channel = ctx.channel();
                ChannelId id = channel.id();
                ChannelMap.removeChannelByName(id);
            } else if (event.state() == IdleState.ALL_IDLE) {
                log.info("Client:{},ALL_IDLE 总超时",socketString);
                ctx.disconnect();
                Channel channel = ctx.channel();
                ChannelId id = channel.id();
                ChannelMap.removeChannelByName(id);
                HashMap map = new HashMap();

            }
        }
    }

    /**
     * 功能描述: 发生异常会触发此函数
     * @Author keLe
     * @Date 2022/8/26
     * @param  ctx 通道处理程序上下文
     * @param  cause 异常
     * @return void
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
//        log.info("{}:发生了错误,此连接被关闭。此时连通数量:{}",ctx.channel().id(),ChannelMap.getChannelMap().size());
//        System.out.println("dwds");
    }
}
